﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using SongeNS;

namespace NewEditorNS
{
    public class CtrlPointManager
    {
        static CtrlPointManager instance;

        public Dictionary<CompVO, List<CtrlPoint>> PointDic;

        #region 初始化

        private GameObject _ctrPointFolder;
        private GameObject ctrlPointFolder
        {
            get
            {
                if (_ctrPointFolder == null)
                {
                    _ctrPointFolder = new GameObject();
                    _ctrPointFolder.name = "__CtrlPointFolder";

                }
                return _ctrPointFolder;
            }
        }

        GameObject _prefabCtrlPoint;
        public GameObject prefabCtrlPoint
        {
            get
            {
                if (_prefabCtrlPoint == null)
                    _prefabCtrlPoint = (GameObject)Resources.Load("SongyiTest/WallCreate/CtrlPoint2");
                return _prefabCtrlPoint;
            }
        }

        public static CtrlPointManager Instance
        {
            get
            {
                if (instance == null)
                    instance = new CtrlPointManager();
                
                return instance;
            }
        }


        public CtrlPointManager()
        {
            initData();
        }


        void initData()
        {
            PointDic = new Dictionary<CompVO, List<CtrlPoint>>();
            //ctrlPointFolder = new GameObject();
            //ctrlPointFolder.name = "__CtrlPointFolder";

            MouseManager.instance.OnMouseEventCallback += onMouseEvent;
        }
        #endregion

        #region 选中管理

        public Action<CtrlPoint> OnCurSelectChange;

        //CtrlPoint curSelect;
        //public CtrlPoint CurSelect
        //{
        //    get { return curSelect; }
        //    set {
        //        CtrlPoint oldPoint = curSelect;
        //        curSelect = value;

        //        if (oldPoint != null)
        //            oldPoint.ShowSelect = false;
        //        if (curSelect != null)
        //            curSelect.ShowSelect = true;

        //        if (OnCurSelectChange != null)
        //            OnCurSelectChange(curSelect);
        //    }
        //}
        #endregion

        #region 控制点管理

        private bool showCtrlPoint = true;
        public bool ShowCtrlPoint
        {
            get
            {
                return showCtrlPoint;
            }

            set
            {
                //Debug.Log("CtrlPointManager~~~~~~~~~~~~~~~~~~~~ShowCtrlPoint"+value);
                showCtrlPoint = value;
                ctrlPointFolder.SetActive(showCtrlPoint);
            }
        }

        public CtrlPoint AddCtrlPoint(CompVO comp, Vector3 pos, CtrlPoint tarPoint, bool needRefresh, bool isMouse = true)
        {
            GameObject pointObject = GameObject.Instantiate(prefabCtrlPoint);
            //EditorUtils.SetLayer(pointObject, LayerTagManager.ctrl_point_layer);
            CtrlPoint newPoint = pointObject.AddComponent<CtrlPoint>();
            newPoint.transform.position = pos;
            newPoint.transform.parent = ctrlPointFolder.transform;
            if (!PointDic.ContainsKey(comp))
                PointDic.Add(comp, new List<CtrlPoint>());
            List<CtrlPoint> pointList = PointDic[comp];


            if (tarPoint == null)
                pointList.Add(newPoint);
            else
                pointList.Insert(pointList.IndexOf(tarPoint), newPoint);


            ////添加侦听
            //addListen("onCtrlPointPress", newPoint, newPoint.onPressDelegate);
            //addListen("onCtrlPointDoubleClick", newPoint, newPoint.onDoubleClickDelegate);
            //addListen("onCtrlPointDragStart", newPoint, newPoint.onDragStartDelegate);
            //addListen("onCtrlPointDraging", newPoint, newPoint.onDragingDelegate);
            //addListen("onCtrlPointDragEnd", newPoint, newPoint.onDragEndDelegate);

            if (needRefresh)
                RefreshCompWallVO(comp);

            return newPoint;
        }

        //void addListen(string funcName, CtrlPoint target, List<EventDelegate> delegateList)
        //{
        //    EventDelegate ed = new EventDelegate(this, funcName);
        //    ed.parameters[0] = new EventDelegate.Parameter();
        //    ed.parameters[0].obj = target;
        //    EventDelegate.Add(delegateList, ed, false);
        //}

        public void RemoveCtrlPoint(GameObject target)
        {
            CtrlPoint ctrlPoint = target.GetComponent<CtrlPoint>();
            RemoveCtrlPoint(ctrlPoint);
        }

        public bool RemoveCtrlPoint(CtrlPoint ctrlPoint)
        {
            CompVO comp = GetCompByCtrlPoint(ctrlPoint);
            List<CtrlPoint> curPointList = PointDic[comp];
            curPointList.Remove(ctrlPoint);
            GameObject.Destroy(ctrlPoint.gameObject);

            if (curPointList.Count == 0)
            {
                CompEditor.Instance.RemoveComp(comp);
                return true;
            }
            else
            {
                RefreshCompWallVO(comp);
            }
            return false;
        }

        public void RemoveWall(CompVO comp)
        {
            if (PointDic.ContainsKey(comp))
            {
                for (int i = 0, length = PointDic[comp].Count; i < length; i++)
                {
                    GameObject.Destroy(PointDic[comp][i].gameObject);
                }

                PointDic.Remove(comp);
            }
        }

        public void SetPointsVisible(bool flag)
        {
            ctrlPointFolder.SetActive(flag);
        }

        #endregion

        #region 结点事件处理

        void onMouseEvent(MouseEvent me)
        {
            if (me.tar is CtrlPoint && me.mouse == 0)
            {
                CtrlPoint target = me.tar as CtrlPoint;
                switch (me.eventType)
                {
                    case MouseEvent.MouseDown:
                        onCtrlPointPress(target);
                        break;
                    case MouseEvent.OnDragStart:
                        onCtrlPointDragStart(target);
                        break;
                    case MouseEvent.OnDraging:
                        onCtrlPointDraging(target);
                        break;
                    case MouseEvent.OnDragEnd:
                        onCtrlPointDragEnd(target);
                        break;
                }
            }
        }


        void onCtrlPointPress(CtrlPoint target)
        {
            //CurSelect = target;
            if (OnCurSelectChange != null)
                OnCurSelectChange(target);
        }

        Vector3 dragStartP = new Vector3();
        Dictionary<CtrlPoint, Vector3> mutilDragBias;
        bool isMultiDrag = false;

        void onCtrlPointDragStart(CtrlPoint target)
        {
            if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
            {
                multiDragStart(target);
            }
            else if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
            {
                CompEditor.Instance.CopyComp(GetCompByCtrlPoint(target));
                multiDragStart(target);
            }
            else
            {
                isMultiDrag = false;
            }
        }
        void multiDragStart(CtrlPoint target)
        {
            isMultiDrag = true;
            mutilDragBias = new Dictionary<CtrlPoint, Vector3>();
            dragStartP = target.transform.position;
            List<CtrlPoint> list = GetPointListByCtrlPoint(target);
            for (int i = 0, length = list.Count; i < length; i++)
            {
                if (list[i] == target)
                    continue;
                mutilDragBias.Add(list[i], dragStartP - list[i].transform.position);
            }
        }

        void onCtrlPointDraging(CtrlPoint target)
        {
            if (target == null || target.gameObject == null)
                return;
            Vector3 dragPoint = SongeUtil.GetMousePointOnHorizontal();
            target.transform.position = dragPoint;

            if (isMultiDrag)
            {
                List<CtrlPoint> list = GetPointListByCtrlPoint(target);
                for (int i = 0, length = list.Count; i < length; i++)
                {
                    if (list[i] == target)
                        continue;
                    list[i].transform.position = target.transform.position - mutilDragBias[list[i]];
                }
            }
        }
        void onMultiDraging(CtrlPoint target)
        {

        }

        void onCtrlPointDragEnd(CtrlPoint target)
        {
            RefreshCompWallVO(target);
        }

        public void RefreshCompWallVO(CtrlPoint target)
        {
            RefreshCompWallVO(GetCompByCtrlPoint(target));
        }
        public void RefreshCompWallVO(CompVO tarComp)
        {
            if (tarComp == null)
            {
                Debug.Log("RefreshCompWallVO param null");
                return;
            }
            List<CtrlPoint> tarPointList = PointDic[tarComp];
            tarComp.theWallVO.PointList = new List<Vector3>();
            for (int i = 0, length = tarPointList.Count; i < length; i++)
            {
                CtrlPoint point = tarPointList[i];
                tarComp.theWallVO.PointList.Add(point.transform.position);
                if (i == 0)
                    tarComp.theWallVO.FirstPoint = point.transform.position;
            }
            tarComp.RefreshModel();
        }

        #endregion

        public CompVO GetCompByCtrlPoint(CtrlPoint point)
        {
            foreach (var pair in PointDic)
            {
                if (pair.Value.Contains(point))
                {
                    return pair.Key;
                }
            }
            return null;
        }

        public List<CtrlPoint> GetPointListByCtrlPoint(CtrlPoint point)
        {
            foreach (var pair in PointDic)
            {
                if (pair.Value.Contains(point))
                {
                    return pair.Value;
                }
            }
            return null;
        }


    }
}
